/* Copyright (c) 2023-2023, LiWangQian<liwangqian@huawei.com> All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "chi/lang/utils/text.h"
#include <algorithm>
#include <cstring>

namespace chi::lang::utils {

bool is_short_string(std::size_t len) noexcept
{
    return len < sizeof(char*);
}

text::~text()
{
    reset();
}

text::text()
{
}

text::text(const char *str, bool copy)
    : text(str, strlen(str), copy)
{   
}

text::text(const char *str, std::size_t len, bool copy)
{
    /* short string never share */
    if (is_short_string(len)) {
        auto mutable_ss = const_cast<char *>(ss_);
        std::copy(str, str + len, mutable_ss);
        mutable_ss[len] = '\0';
        size_ = len;
        owns_ls_ = false;
        return;
    }

    if (!copy) {
        ls_ = str;
        size_ = len;
        owns_ls_ = false;
        return;
    }

    ls_ = new char[len + 1];
    auto mutable_ls = const_cast<char *>(ls_);
    std::copy(str, str + len, mutable_ls);
    mutable_ls[len] = '\0';
    size_ = len;
    owns_ls_ = true;
}

text::text(const std::string &str)
    : text(str.c_str(), str.length(), true)
{
}

text::text(const std::string_view &str)
    : text(str.data(), str.length())
{
}

text::text(const text &other)
    : text(other.data(), other.length(), other.shared())
{
}

text::text(text &&other) noexcept
{
    swap(other);
}

text &text::operator=(const text &other)
{
    if (this != &other) {
        text tmp{other};
        swap(tmp);
    }
    return *this;
}

text &text::operator=(text &&other) noexcept
{
    swap(other);
    return *this;
}

int text::compara(const text &t) const noexcept
{
    return compara(t.data());
}

int text::compara(const char *str) const noexcept
{
    return strcmp(data(), str);
}

int text::compara(const std::string_view &str) const noexcept
{
    return compara(str.data());
}

int text::compara(const std::string &str) const noexcept
{
    return compara(str.c_str());
}

void text::reset() noexcept
{
    if (is_short_string(size_)) {
        ls_ = nullptr; /* clear ss[8] */
        size_ = 0;
        return;
    }

    if (ls_ != nullptr) {
        if (owns_ls_) {
            owns_ls_ = false;
            delete ls_;
        }
        size_ = 0;
        ls_ = nullptr;
    }
}

void text::swap(text &other) noexcept
{
    if (this != &other) {
        std::swap(ls_, other.ls_);
        std::swap(size_, other.size_);
        std::swap(owns_ls_, owns_ls_);
    }
}

bool text::shared() const noexcept
{
    return !is_short_string(size_) && !owns_ls_;
}

const char *text::data() const noexcept
{
    return is_short_string(size_) ? ss_ : ls_;
}

} // namespace chi::lang::utils
